import {
  Checkbox,
  InputNumber,
  Modal,
  Form,
  Input,
  Select,
  Button,
  message,
  Switch,
  Col,
} from 'antd'
import c from 'classnames'
import { pick } from 'lodash'
import { useStreams } from '@/lib/utils'
import services from '@/services'
import type { WarnRule, GeneralWarnRule } from '@/services/features/sensitive-warns'
import {
  WarnRuleType,
  DEFAULT_DELAY_TIMEOUT,
  DEFAULT_DELAY_NEW_LIMIT,
} from '@/services/features/sensitive-warns'
import './Edit.module.less'

export default function EditModal(props: {
  editing: false | true | WarnRule
  onFinish: () => void
}) {
  const { editing, onFinish } = props

  const title = editing !== false ? (editing === true ? '新建规则' : '编辑规则') : ''

  return <Modal
    title={title}
    footer={null}
    width="500px"
    open={editing !== false}
    onCancel={onFinish}
    destroyOnClose
  >
    {editing !== false ? <Content editing={editing} onFinish={onFinish} /> : null}
  </Modal>
}

const LABEL_SPAN = 6

function Content(props: { editing: true | WarnRule; onFinish: () => void }) {
  const { editing, onFinish } = props
  const [isAdmin] = useStreams(services.auth.isAdmin$)
  const [form] = Form.useForm<FormValues>()

  type FormValues = typeof initialValues
  const initialValues = useMemo(() => {
    const defaultDelayConfig = {
      timeout: DEFAULT_DELAY_TIMEOUT,
      newOnly: false,
      newLimit: DEFAULT_DELAY_NEW_LIMIT,
    }
    return editing === true
      ? {
          name: '',
          type: WarnRuleType.Exact,
          isGlobal: isAdmin === true,
          keyword: '',
          ...defaultDelayConfig,
        }
      : {
          ...pick(editing, 'name', 'type', 'isGlobal'),
          keyword: editing.type === WarnRuleType.Delay ? '' : editing.content,
          ...(editing.type === WarnRuleType.Delay ? editing.content : defaultDelayConfig),
        }
  }, [editing, isAdmin])

  const keywordValidator = useCallback(
    async (_: unknown, value: GeneralWarnRule['content']) => {
      const ruleType = form.getFieldValue('type') as FormValues['type']
      if (ruleType === WarnRuleType.Delay) return Promise.resolve() // delay 类型时不验证此字段
      if (!value)
        throw new Error(ruleType === WarnRuleType.Regex ? '请输入正则表达式' : '请输入关键词')

      // 如果匹配类型是“正则匹配”，则检查输入的正则表达式是否合法
      if (ruleType === WarnRuleType.Regex) {
        try {
          new RegExp(value)
        } catch {
          throw new Error('请输入正确的正则表达式')
        }
      }

      return Promise.resolve()
    },
    [form],
  )

  const [submitting, setSubmitting] = useState(false)
  const submit = useCallback(
    async (values: typeof initialValues) => {
      setSubmitting(true)
      const res = await services.features.sensitiveWarns.addOrUpdate({
        id: editing === true ? undefined : editing.id,
        enable: editing === true ? true : editing.enable,
        ...pick(values, 'name', 'type', 'isGlobal'),
        content:
          values.type === WarnRuleType.Delay
            ? pick(values, 'timeout', 'newOnly', 'newLimit')
            : values.keyword,
      })
      setSubmitting(false)
      if (res.success) {
        void message.success('保存成功')
        onFinish()
      } else {
        void message.warning(`保存失败：${res.error}`)
      }
    },
    [editing, onFinish],
  )

  return <Form
    styleName="edit"
    labelCol={{ span: LABEL_SPAN }}
    form={form}
    initialValues={initialValues}
    onFinish={submit}
  >
    <Form.Item rules={[{ required: true }]} label="规则名称" name="name">
      <Input />
    </Form.Item>

    <Form.Item label="匹配类型" name="type">
      <Select>
        <Select.Option value={WarnRuleType.Exact}>关键词精确匹配</Select.Option>
        <Select.Option value={WarnRuleType.Fuzzy}>关键词包含匹配</Select.Option>
        <Select.Option value={WarnRuleType.Regex}>关键词正则匹配</Select.Option>
        <Select.Option value={WarnRuleType.Delay}>超时未回复</Select.Option>
      </Select>
    </Form.Item>

    <Form.Item shouldUpdate noStyle>
      {() => {
        const isGeneral = form.getFieldValue('type') !== WarnRuleType.Delay
        return <Form.Item
          hidden={!isGeneral}
          rules={[{ required: isGeneral, validator: keywordValidator }]}
          label="关键词或正则"
          name="keyword"
        >
          <Input />
        </Form.Item>
      }}
    </Form.Item>

    <Form.Item shouldUpdate noStyle>
      {() => {
        const isDelay = form.getFieldValue('type') === WarnRuleType.Delay
        const isNewOnly = form.getFieldValue('newOnly') as FormValues['newOnly']
        const isNewLimitRequired = isDelay && isNewOnly
        const newLimitError = form.getFieldError('newLimit')
        return <>
          <Form.Item
            hidden={!isDelay}
            rules={[{ required: true, message: '请输入超时分钟范围' }]}
            label="超时规则"
            name="timeout"
          >
            <TimeoutInput />
          </Form.Item>
          <Col offset={LABEL_SPAN} styleName={c('delay-new', !isDelay && 'hidden')}>
            <Form.Item noStyle name="newOnly" valuePropName="checked">
              <Checkbox>仅针对新好友前</Checkbox>
            </Form.Item>
            <Form.Item
              noStyle
              name="newLimit"
              rules={[{ required: isNewLimitRequired, message: '请输入新消息条数' }]}
            >
              <NewLimitInput disabled={!isNewOnly} />
            </Form.Item>
            {isNewLimitRequired && newLimitError.length ? (
              <div styleName="new-limit-error">{newLimitError[0]}</div>
            ) : null}
          </Col>
        </>
      }}
    </Form.Item>

    <Form.Item
      hidden={isAdmin !== true}
      label="是否为全局规则"
      name="isGlobal"
      valuePropName="checked"
    >
      <Switch checkedChildren="是" unCheckedChildren="否" />
    </Form.Item>

    <Form.Item wrapperCol={{ offset: LABEL_SPAN }}>
      <Button loading={submitting} type="primary" htmlType="submit">
        保存
      </Button>
    </Form.Item>
  </Form>
}

function TimeoutInput(props: Record<string, unknown>) {
  return <>
    <InputNumber {...props} min={1} max={20} placeholder="1～20" />
    <span styleName="timeout-input-tip">分钟内未回复</span>
  </>
}

function NewLimitInput(props: Record<string, unknown>) {
  return <>
    <InputNumber {...props} min={1} max={1000} placeholder="1～1000" />
    <span>条消息生效</span>
  </>
}
